/**
 * Created by qiushaohua on 15-1-27.
 */
define([
    'app',
    'jquery',
    'jqueryIndexeddb'
], function (app, $) {

    'use strict';

    var DB_NAME = 'isw-db';

    var deps = [ '$q' ];

    function service($q) {

        var db = $.indexedDB(DB_NAME);

        function doWithStore(action, storeName, obj, mode) {
            var defer = $q.defer();
            var transPromise = db.transaction(storeName, mode || 'readwrite');
            transPromise.progress(function inTrans(trans) {
                var store = trans.objectStore(storeName);
                var promise = store[action](obj);
                promise.then(function onSuccess(result) {
                    defer.resolve(result);
                }, function onError(error, event) {
                    console.error(event);
                    defer.reject(event);
                });
            });
            return defer.promise;
        }

        function doArrayWithStore(action, storeName, list, mode) {
            var defer = $q.defer();
            if (!list || list.length === 0) {
                defer.resolve();
                return defer.promise;
            }

            var transPromise = db.transaction(storeName, mode || 'readwrite');
            transPromise.progress(function inTrans(trans) {
                var store = trans.objectStore(storeName);

                var promises = [];
                for (var i = 0, len = list.length; i < len; i++) {
                    var obj = list[i];
                    var promise = store[action](obj);
                    promises.push(promise);
                }

                $q.all(promises).then(function onSuccess(result) {
                    defer.resolve(result);
                }, function onError(error, event) {
                    console.error(event);
                    defer.reject(event);
                });
            });
            return defer.promise;
        }

        return {
            save: function addContentToLocal(store, obj) {
                return doWithStore('add', store, obj);
            },
            saveOrUpdate: function putContentToLocal(store, obj) {
                return doWithStore('put', store, obj);
            },
            delete: function removeContentAtLocal(store, key) {
                return doWithStore('delete', store, key);
            },
            get: function getContentFromLocal(store, key) {
                return doWithStore('get', store, key, 'readonly');
            },

            saveArray: function addContentsToLocal(store, list) {
                return doArrayWithStore('add', store, list);
            },
            saveOrUpdateArray: function putContentsToLocal(store, list) {
                return doArrayWithStore('put', store, list);
            },
            deleteArray: function removeContentsAtLocal(store, keys) {
                return doArrayWithStore('delete', store, keys);
            },

            queryByIndex: function queryByIndex(storeName, indexName, limit, range, direction) {
                var defer = $q.defer();
                var transPromise = db.transaction(storeName, 'readonly');
                transPromise.progress(function inTrans(trans) {
                    var store = trans.objectStore(storeName);
                    var index = store.index(indexName);

                    var items = [];
                    var i = 0;
                    var limitType = typeof limit;
                    var promise = index.each(function eachItem(item) {
                        items.push(item.value);
                        i++;
                        if (limit && limitType === 'number' && i === limit) {
                            return false;
                        }
                        if (limit && limitType === 'function') {
                            var isLimited = limit(item.value, i);
                            if (isLimited) {
                                return false;
                            }
                        }
                    }, range, direction);

                    promise.then(function onSuccess() {
                        defer.resolve(items);
                    }, function onError(error) {
                        defer.reject(error);
                    });
                });
                return defer.promise;
            }
        };
    }

    /**
     * 创建 Object Store
     * 这里的最大的key 值是DB 的版本号. indexedDB 只会执行比当前浏览器中版本号大的schema.
     *
     * note: 每次需要添加新的Object Store 时, 不能直接在当前的方法里面添加, 应该是添加一个新的key (按数字递增), 以及对应的函数.
     * 加入下面schema 最大的key 值是 5, 现在要新增一个 'channel' 的Object Store, 那么schema 就需要添加一个key 为6 的属性, 变成:
     *
     * schema = {
     *     1: ...,
     *     2: ...,
     *     ...
     *     5: ...,
     *     6: function schemaV6 (trans) {
     *         trans.createObjectStore('channel', {
     *             keyPath: 'topicItemId'
     *         });
     *     }
     * }
     */
    var schema = {
        1: function schemaV1(trans) {
            var chatStore = trans.createObjectStore('chat', {
                keyPath: 'topicItemId'
            });
            chatStore.createIndex(['topicId', 'createDate'], {
                unique: false
            }, 'topicId');

            trans.createObjectStore('chatSendContent', {
                keyPath: 'topicId'
            });
        },
        2: function schemaV2(trans) {
            trans.createObjectStore('channelItemCommentContent', {
                keyPath: 'itemId'
            });
        },
        3: function schemaV3(trans) {
            trans.createObjectStore('userSettings', {
                keyPath: 'userId'
            });
        }
    };

    function initDB() {
        $.indexedDB(DB_NAME, {
            schema: schema
        });
    }

    initDB();

    service.$inject = deps;
    app.lazy.service('DBService', service);
});
